#pragma once
/**
 * 实现TcpClient类
 * 它封装TcpConnector与TcpConnection两个对象
 */

#include "base/uncopyable.hpp"
#include "event/loop.hpp"
#include "network/byte_stream.hpp"
#include "network/sockaddr.hpp"

namespace ibox::network {

class TcpConnector;
class TcpConnection;

using namespace base;
class TcpClient : public Uncopyable, public ByteStream {
public:
    explicit TcpClient(event::Loop *loop);
    ~TcpClient() override;

    using ConnectedCallback = std::function<void()>;
    using DisconnectedCallback = std::function<void()>;

    //!< 状态
    enum class State {
        None,       //!< 未初始化
        Inited,     //!< 已初始化
        Connecting, //!< 连接中
        Connected   //!< 连接成功
    };

public:
    bool initialize(const SockAddr &server_addr);
    void set_connected_callback(const ConnectedCallback &cb);
    void set_disconnected_callback(const DisconnectedCallback &cb);
    void set_auto_reconnect(bool enable);

    bool start(); //!< 开始连接服务端
    void stop(); //!< 如果没有连接则成，则停止连接；否则断开连接

    bool shutdown(int howto); //! 支持半关闭
    void cleanup();

    State state() const;

public: //! 实现ByteStream的接口
    void set_receive_callback(ReceiveCallback cb, size_t threshold) override;
    bool send(const void *data_ptr, size_t data_size) override;
    void bind(ByteStream *receiver) override;
    void unbind() override;

protected:
    void on_tcp_connected(TcpConnection *new_conn);
    void on_tcp_disconnected();

private:
    struct Data;
    std::unique_ptr<Data> m_data{};
};
} // namespace ibox::network
